package pe.gob.mininter.dirandro.vaadin.panel.seguridad;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;

import pe.gob.mininter.dirandro.model.Opcion;
import pe.gob.mininter.dirandro.model.Permiso;
import pe.gob.mininter.dirandro.model.Rol;
import pe.gob.mininter.dirandro.model.Valor;
import pe.gob.mininter.dirandro.service.OpcionService;
import pe.gob.mininter.dirandro.service.PermisoService;
import pe.gob.mininter.dirandro.service.RolService;
import pe.gob.mininter.dirandro.service.ValorService;
import pe.gob.mininter.dirandro.util.Constante;
import pe.gob.mininter.dirandro.vaadin.util.DirandroComponent;
import pe.gob.mininter.dirandro.vaadin.util.Injector;

import com.vaadin.annotations.AutoGenerated;
import com.vaadin.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
import com.vaadin.ui.TreeTable;
import com.vaadin.ui.VerticalLayout;


@SuppressWarnings("serial")
public class PanelSegPermiso extends DirandroComponent implements ClickListener{

	@AutoGenerated
    private VerticalLayout mainLayout;
    @AutoGenerated
    private Button btnGrabar;
    @AutoGenerated
    private HorizontalLayout pnlListaContenido;
    @AutoGenerated
    private VerticalLayout pnlOpciones;
    @AutoGenerated
    private TreeTable treeOpciones;
    @AutoGenerated
    private Label lblOpciones;
    @AutoGenerated
    private VerticalLayout pnlRoles;
    @AutoGenerated
    private Table tblRoles;
    @AutoGenerated
    private Label lblRoles;
    Map<String, List<Opcion>> map;

    @Autowired
    private RolService rolService;
    @Autowired
    private PermisoService permisoService;
    @Autowired
    private OpcionService opcionService;
    @Autowired
    private ValorService valorService;
    
	/**
	 * The constructor should first build the main layout, set the
	 * composition root and then do any custom initialization.
	 *
	 * The constructor will not be automatically regenerated by the
	 * visual editor.
	 */
	public PanelSegPermiso(List<Opcion> acciones, String height) {
		super(acciones, height);
		buildMainLayout();
		setCompositionRoot(mainLayout);
		rolService=Injector.obtenerServicio(RolService.class);
		permisoService=Injector.obtenerServicio(PermisoService.class);
		opcionService=Injector.obtenerServicio(OpcionService.class);
		valorService=Injector.obtenerServicio(ValorService.class);
		postConstruct();
	}

	public void postConstruct() {
        List<Rol> roles = rolService.buscarRoles(null);
		cargarRoles(roles);
		
		tblRoles.setSelectable(true);
		tblRoles.setImmediate(true);
		tblRoles.setNullSelectionAllowed(true);
		tblRoles.setNullSelectionItemId(null);
		
		cargarOpciones();
		
		btnGrabar.setEnabled(false);
		
		tblRoles.addListener(new ValueChangeListener() {
		
		        @Override
		        public void valueChange(ValueChangeEvent event) {
		                
		                btnGrabar.setEnabled(false);
		                
		                List<Permiso> permisos = null;
		                if(tblRoles.getValue() != null)
		                {
		                        Long idRol = obtenerIdRolSeleccionado();
		                        permisos = permisoService.obtenerPermisosXRol(idRol, true);
		                        btnGrabar.setEnabled(true);
		                }
		                
		                limpiarOpciones();
		                
		                if(permisos != null)
		                {
		                        for (Permiso permiso : permisos) {
		                                Item item = obtenerItemOpcion(permiso.getOpcion().getId());
		                                if(item != null)
		                                {
		                                        setCheckBoxOpcion(item, true);
		                                }
		                        }
		                }                               
		        }
		        
		});
		
		btnGrabar.addListener((ClickListener)this);
	}
	
	@Override
	public void buttonClick(ClickEvent event) {
		if(event.getButton().equals(btnGrabar)){
			buttonClickGrabar();
		}
	}
	
	@SuppressWarnings("rawtypes")
	private void buttonClickGrabar(){

        Long idRol = obtenerIdRolSeleccionado();
        List<Long> idsOpciones = new ArrayList<Long>();
        
        Collection lista = treeOpciones.getItemIds();
        for (Iterator i = lista.iterator(); i.hasNext(); )
        {
                Object valor = i.next();
                Item item = treeOpciones.getItem(valor);
                CheckBox chk = (CheckBox) item.getItemProperty("permiso").getValue();
                if(chk.booleanValue())
                {
                        Long idOpcion = (Long) item.getItemProperty("id").getValue();
                        idsOpciones.add(idOpcion);
                }
        }
        //permisoService.guardarPermisos(idRol, idsOpciones);
        
        List<Permiso> permisosALL = permisoService.obtenerPermisosXRol(idRol, false);
        List<Permiso> permisosA = permisoService.obtenerPermisosXRol(idRol, true);
        List<Permiso> permisosSel = new ArrayList<Permiso>();
        for (Long idOpcion : idsOpciones) {
                Permiso permiso = new Permiso();
                permiso.setRol(new Rol());
                permiso.getRol().setId(idRol);
                permiso.setOpcion(new Opcion());
                permiso.getOpcion().setId(idOpcion);
                permisosSel.add(permiso);
        }
        List<Permiso> permisosD = ListUtils.subtract(permisosALL, permisosA);
        
        List<Permiso> updPermisosD = ListUtils.subtract(permisosA, permisosSel);
        List<Permiso> updPermisosA = ListUtils.intersection(permisosSel, permisosD);
        List<Permiso> insPermisosA = ListUtils.subtract(permisosSel, permisosALL);
		
		Valor estadoInactivo = valorService.obtenerValor(Constante.LISTA.CODIGO.ESTADO, Constante.VALOR.CODIGO.INACTIVO);
		Valor estadoActivo = valorService.obtenerValor(Constante.LISTA.CODIGO.ESTADO, Constante.VALOR.CODIGO.ACTIVO);
		
		permisoService.prepararLista(updPermisosD, estadoInactivo);
		permisoService.prepararLista(updPermisosA, estadoActivo);
		permisoService.prepararLista(insPermisosA, estadoActivo);
        
        List<Permiso> permisosU = ListUtils.union(updPermisosD, updPermisosA);
        List<Permiso> permisos = ListUtils.union(permisosU, insPermisosA);
        
        permisoService.grabarTodos(permisos);
        
        
        
        
	}
	
	private Long obtenerIdRolSeleccionado()
    {
            Item item = tblRoles.getItem(tblRoles.getValue());
            return (Long) item.getItemProperty("id").getValue();
    }
	
	@SuppressWarnings("rawtypes")
    private void limpiarOpciones() {
            Collection lista = treeOpciones.getItemIds();
            for (Iterator i = lista.iterator(); i.hasNext(); )
            {
                    Object valor = i.next();
                    Item item = treeOpciones.getItem(valor);
                    setCheckBoxOpcion(item, false);
            }
    }
	
	private void setCheckBoxOpcion(Item item, boolean flag)
    {
            CheckBox chk = (CheckBox) item.getItemProperty("permiso").getValue();
            chk.setValue(flag);
    }
	
	@SuppressWarnings("rawtypes")
    private Item obtenerItemOpcion(Long idOpcion)
    {
            Collection lista = treeOpciones.getItemIds();
            for (Iterator i = lista.iterator(); i.hasNext(); )
            {
                    Object valor = i.next();
                    Item item = treeOpciones.getItem(valor);
                    Long opcion = (Long) item.getItemProperty("id").getValue();
                    if(idOpcion.longValue() == opcion.longValue())
                    {
                            return item;
                    }
            }
            return null;
    }
	
	private void cargarOpciones() {
        
//      Map<String, List<Opcion>> 
        map = opcionService.listarOpciones();
        
        CheckBox chk = new CheckBox();
        chk.addListener(this);
        
        treeOpciones.addContainerProperty("permiso", CheckBox.class, chk);
        treeOpciones.addContainerProperty("tipo", String.class, "");
        treeOpciones.addContainerProperty("id", Long.class, 0L);
        treeOpciones.setImmediate(true);
        
        recorrer(Constante.OPCION.KEY_PADRE, map, null);
        
        treeOpciones.setVisibleColumns(new Object[]{"permiso", "tipo"});
	}
	
	public void seleccionarHijos(Object opcion,boolean valor){              
        Collection<?> lstHijos=treeOpciones.getChildren(opcion);
        if(lstHijos==null)return;
        for (Object hijo : lstHijos) {
                Item item = treeOpciones.getItem(hijo);
                if(item != null)
                {
                        setCheckBoxOpcion(item, valor);
                        seleccionarHijos(hijo, valor);
                }
        }
	}

	public void deseleccionarPadre(Object opcion,boolean valor){
	        int seleccionados=0;
	        Object parent=treeOpciones.getParent(opcion);
	        Collection<?> lstHijos=treeOpciones.getChildren(parent);
	        if(lstHijos==null)return;
	        for (Object hijo : lstHijos) {
	                Item item = treeOpciones.getItem(hijo);
	                if(item != null)
	                {
	                        CheckBox chk = (CheckBox) item.getItemProperty("permiso").getValue();
	                        if(chk.booleanValue()){
	                                seleccionados++;
	                        }
	                }
	        }
	        if(seleccionados==0){setCheckBoxOpcion(treeOpciones.getItem(parent), false);
	        }else{setCheckBoxOpcion(treeOpciones.getItem(parent), true);}
	        deseleccionarPadre(parent,false);
	}
	
	private void recorrer(String codigo, Map<String, List<Opcion>> map, Object objPadre) {
        for (Opcion opc : map.get(codigo)) {
                
                CheckBox chk = new CheckBox(opc.getNombre());
                //chk.setData(opc.getId());
                chk.setImmediate(true);
                chk.addListener(new ClickListener() {

                        private static final long serialVersionUID = -2056672559324022605L;

                        @Override
                        public void buttonClick(ClickEvent event) {
                                CheckBox chkAux=(CheckBox)event.getSource();
                                boolean valor=Boolean.parseBoolean(event.getSource().toString());
                                Object opcion = chkAux.getData();
                                seleccionarHijos(opcion,valor);
//                              if(!valor){
                                        deseleccionarPadre(opcion,false);
//                              }
                        }
                });
                
                Object opcion = treeOpciones.addItem(new Object[] { chk,
                                opc.getNombre(), opc.getId()}, null);
                chk.setData(opcion);
                //treeOpciones.get
                
                if (!codigo.equals(Constante.OPCION.KEY_PADRE)) {
                        treeOpciones.setParent(opcion, objPadre);
                }

                if (map.get(opc.getCodigo()) != null) {
                        treeOpciones.setCollapsed(opcion, false);
                        recorrer(opc.getCodigo(), map, opcion);
                } else {
                        treeOpciones.setChildrenAllowed(opcion, false);
                }
        }
	}
	
	private void cargarRoles(List<Rol> roles)
    {
            IndexedContainer container = new IndexedContainer();
            
            container.addContainerProperty("id", Long.class,  null);
            container.addContainerProperty("codigo", String.class,  null);
            container.addContainerProperty("nombre", String.class, null);
            container.addContainerProperty("descripcion", String.class, null);
            
            int con=1;
            for (Rol rol : roles) {
                    Item item = container.addItem(con++);
                    item.getItemProperty("id").setValue(rol.getId());
			        item.getItemProperty("codigo").setValue(rol.getCodigo());
			        item.getItemProperty("nombre").setValue(rol.getNombre());
			        item.getItemProperty("descripcion").setValue(rol.getDescripcion());
            }
            
            tblRoles.setContainerDataSource(container);
            tblRoles.setVisibleColumns(new Object[]{"codigo", "nombre", "descripcion"});
            tblRoles.setColumnWidth("codigo", 90);
            tblRoles.setColumnWidth("nombre", 150);
            tblRoles.setColumnWidth("descripcion", 180);
            tblRoles.setColumnHeader("codigo", "Código");
            tblRoles.setColumnHeader("nombre", "Nombre");
            tblRoles.setColumnHeader("descripcion", "Descripción");         
    }
	
	@AutoGenerated
    private VerticalLayout buildMainLayout() {
            // common part: create layout
            mainLayout = new VerticalLayout();
            mainLayout.setImmediate(false);
            mainLayout.setWidth("100%");
            mainLayout.setHeight("100%");
            mainLayout.setMargin(false);
            
            // top-level component properties
            setWidth("100.0%");
            setHeight("100.0%");
            
            // pnlListaContenido
            pnlListaContenido = buildPnlListaContenido();
            mainLayout.addComponent(pnlListaContenido);
            
            // btnGrabar
            btnGrabar = new Button();
            btnGrabar.setCaption("Grabar");
            btnGrabar.setImmediate(true);
            btnGrabar.setWidth("-1px");
            btnGrabar.setHeight("-1px");
            mainLayout.addComponent(btnGrabar);
            
            return mainLayout;
    }

    @AutoGenerated
    private HorizontalLayout buildPnlListaContenido() {
            // common part: create layout
            pnlListaContenido = new HorizontalLayout();
            pnlListaContenido.setImmediate(false);
            pnlListaContenido.setWidth("-1px");
            pnlListaContenido.setHeight("-1px");
            pnlListaContenido.setMargin(true);
            
            // pnlRoles
            pnlRoles = buildPnlRoles();
            pnlListaContenido.addComponent(pnlRoles);
            
            // pnlOpciones
            pnlOpciones = buildPnlOpciones();
            pnlListaContenido.addComponent(pnlOpciones);
            
            return pnlListaContenido;
    }

    @AutoGenerated
    private VerticalLayout buildPnlRoles() {
            // common part: create layout
            pnlRoles = new VerticalLayout();
            pnlRoles.setImmediate(false);
            pnlRoles.setWidth("500px");
            pnlRoles.setHeight("-1px");
            pnlRoles.setMargin(false);
            pnlRoles.setSpacing(true);
            
            // lblRoles
            lblRoles = new Label();
            lblRoles.setImmediate(false);
            lblRoles.setWidth("-1px");
            lblRoles.setHeight("-1px");
            lblRoles.setValue("Roles");
            pnlRoles.addComponent(lblRoles);
            
            // tblRoles
            tblRoles = new Table();
            tblRoles.setImmediate(false);
            tblRoles.setWidth("480px");
            tblRoles.setHeight("400px");
            pnlRoles.addComponent(tblRoles);
            
            return pnlRoles;
    }

    @AutoGenerated
    private VerticalLayout buildPnlOpciones() {
            // common part: create layout
            pnlOpciones = new VerticalLayout();
            pnlOpciones.setImmediate(false);
            pnlOpciones.setWidth("-1px");
            pnlOpciones.setHeight("-1px");
            pnlOpciones.setMargin(false);
            pnlOpciones.setSpacing(true);
            
            // lblOpciones
            lblOpciones = new Label();
            lblOpciones.setImmediate(false);
            lblOpciones.setWidth("-1px");
            lblOpciones.setHeight("-1px");
            lblOpciones.setValue("Opciones");
            pnlOpciones.addComponent(lblOpciones);
            
            // treeOpciones
            treeOpciones = new TreeTable();
            treeOpciones.setImmediate(false);
            treeOpciones.setWidth("400px");
            treeOpciones.setHeight("400px");
            pnlOpciones.addComponent(treeOpciones);
            
            return pnlOpciones;
    }

}
